import com.intellij.database.model.DasTable
import com.intellij.database.model.ObjectKind
import com.intellij.database.util.Case
import com.intellij.database.util.DasUtil

/*
 * Available context bindings:
 *   SELECTION   Iterable<DasObject>
 *   PROJECT     project
 *   FILES       files helper
 */

packageName = ""
projectName = ""
modelName = ""
upperCaseModelName = ""

typeMapping = [
        (~/(?i)tinyint|smallint|mediumint/)      : "Integer",
        (~/(?i)int/)                             : "Long",
        (~/(?i)bool|bit/)                        : "Boolean",
        (~/(?i)float|double|decimal|real/)       : "Double",
        (~/(?i)datetime|timestamp|date|time/)    : "Date",
        (~/(?i)blob|binary|bfile|clob|raw|image/): "InputStream",
        (~/(?i)/)                                : "String"
]

FILES.chooseDirectoryAndSave("Choose directory", "Choose where to store generated files") { dir ->
  SELECTION.filter { it instanceof DasTable && it.getKind() == ObjectKind.TABLE }.each { generate(it, dir) }
}

def generate(table, dir) {
  modelName = javaName(table.getName(), true)
  modelName = modelName.replaceFirst("Pontiac","")



  projectName = getProjectName(dir)
  upperCaseModelName = getUpperCaseModelName(modelName)

  def className = modelName+"DO"
  def fields = calcFields(table)
  packageName = getPackageName(dir)

  def fos=new FileOutputStream(new File(dir, modelName + "RepoTest.java"))
  def osw=new OutputStreamWriter(fos, "UTF-8")
  def  bw = new BufferedWriter(osw)
  generate(bw, className, fields)
  bw.close();
  osw.close();
  fos.close();
}

def getProjectName(dir) {
  return dir.toString().replaceAll("\\\\", ".")
          .replaceAll("^.*src(\\.test\\.java\\.)?", "")
          .replaceAll("(com\\.pajk\\.)?","")
          .split("\\.")[0]
}

def getUpperCaseModelName(upperCaseModelName) {
  def firstStr = upperCaseModelName.substring(0,1).toLowerCase()
  def nextStr = upperCaseModelName.substring(1,upperCaseModelName.size())
  return firstStr+nextStr
}

def getLowerCaseFieldsName(lowerCaseModelName) {
  def firstStr = lowerCaseModelName.substring(0,1).toUpperCase()
  def nextStr = lowerCaseModelName.substring(1,lowerCaseModelName.size())
  return firstStr+nextStr
}


/**
 * 获取包名称
 * @param dir 实体类所在目录
 * @return
 */
def getPackageName(dir) {
  return dir.toString().replaceAll("\\\\", ".").replaceAll("^.*src(\\.main\\.java\\.)?", "") + ";"
}

def generate(out, className, fields) {

  out.write("package com.pajk.${projectName}.test.repo; \n")
  out.write("\n")

  Set types = new HashSet()

  fields.each() {
    types.add(it.type)
  }

  if (types.contains("Date")) {
    out.write("import java.util.Date;\n")
  }

  if (types.contains("InputStream")) {
    out.write("import java.io.InputStream;\n")
  }
  out.write("import org.junit.Test;\n")
  out.write("import org.junit.Assert;\n")
  out.write("import javax.annotation.Resource;\n")
  out.write("import com.pajk.${projectName}.test.BaseTest;\n")
  out.write("import com.pajk.${projectName}.core.repo.${modelName}Repo;\n")
  out.write("import com.pajk.${projectName}.core.dal.model.${modelName}DO;\n")
  out.write("\n")
  out.write("public class ${modelName}RepoTest extends BaseTest {\n")
  out.write("\n")
  out.write("\t@Resource\n")
  out.write("\tprivate ${modelName}Repo ${upperCaseModelName}Repo;\n")
  out.write("\n")
  out.write("\t@Test\n")
  out.write("\tpublic void insert() {\n")
  out.write("\t\t${modelName}DO param = new ${modelName}DO();\n")
  def random = new Random()
  fields.each() {
    if ("id".equals(it.name) || it.name == "gmtCreated" || it.name == "gmtModified"){
      return;
    }
    def fieldName = getLowerCaseFieldsName(it.name)
    if(it.name == "romaEnvIndicator"){
      out.write("\t\tparam.set${fieldName}(\"dev\");\n")
      return ;
    }
    if(it.name == "status"){
      out.write("\t\tparam.set${fieldName}(1);\n")
      return ;
    }

    if (it.annos != "") out.write("  ${it.annos}\n")

    // 输出成员变量
    if (it.type.equals("String")) {
      out.write("\t\tparam.set${fieldName}(\"${fieldName}\");\n")
    }
    if (it.type.equals("Long")) {
      out.write("\t\tparam.set${fieldName}(${ random.nextInt(900000)}l);\n")
    }
    if (it.type.equals("Integer")) {
      out.write("\t\tparam.set${fieldName}(${ random.nextInt(900000)});\n")
    }
    if (it.type.equals("Date")) {
      out.write("\t\tparam.set${fieldName}(new Date());\n")
    }
  }
  out.write("\t\t${upperCaseModelName}Repo.insert(param);\n")
  out.write("\t}\n")

  out.write("\n")
  out.write("\t@Test\n")
  out.write("\tpublic void update() {\n")
  out.write("\t\t${modelName}DO param = new ${modelName}DO();\n")
  fields.each() {
    if (it.name == "gmtCreated" || it.name == "gmtModified"){
      return;
    }
    def fieldName = getLowerCaseFieldsName(it.name)
    if(it.name == "id"){
      out.write("\t\tparam.set${fieldName}(1l);\n")
      return ;
    }
    if(it.name == "romaEnvIndicator"){
      out.write("\t\tparam.set${fieldName}(\"dev\");\n")
      return ;
    }
    if(it.name == "status"){
      out.write("\t\tparam.set${fieldName}(2);\n")
      return ;
    }
    if (it.annos != "") out.write("  ${it.annos}\n")

    // 输出成员变量
    if (it.type.equals("String")) {
      out.write("\t\tparam.set${fieldName}(\"Update ${fieldName}\");\n")
    }
    if (it.type.equals("Long")) {
      out.write("\t\tparam.set${fieldName}(${ random.nextInt(900000)}l);\n")
    }
    if (it.type.equals("Integer")) {
      out.write("\t\tparam.set${fieldName}(${ random.nextInt(900000)});\n")
    }
    if (it.type.equals("Date")) {
      out.write("\t\tparam.set${fieldName}(new Date());\n")
    }
  }
  out.write("\t\t${upperCaseModelName}Repo.update(param);\n")
  out.write("\t}\n")

  out.write("\n")
  out.write("\t@Test\n")
  out.write("\tpublic void getById() {\n")
  out.write("\t\t${modelName}DO result = ${upperCaseModelName}Repo.getById(1l);\n")
  out.write("\t\tSystem.out.println(\"Result>>>\"+result);\n")
  out.write("\t\tAssert.assertNotNull(result);\n")
  out.write("\t}\n")




  out.write("\n")
  out.write("}\n")
  return out.toString();
}

def calcFields(table) {
  DasUtil.getColumns(table).reduce([]) { fields, col ->
    def spec = Case.LOWER.apply(col.getDataType().getSpecification())
    def typeStr = typeMapping.find { p, t -> p.matcher(spec).find() }.value
    fields += [[
                       colName : col.getName(),
                       name    : javaName(col.getName(), false),
                       type    : typeStr,
                       commoent: col.getComment(),
                       annos   : ""]]
  }
}

def javaName(str, capitalize) {
  def s = str.split(/(?<=[^\p{IsLetter}])/).collect { Case.LOWER.apply(it).capitalize() }
          .join("").replaceAll(/\_/, "")
  capitalize || s.length() == 1? s : Case.LOWER.apply(s[0]) + s[1..-1]
}

def isNotEmpty(content) {
  return content != null && content.toString().trim().length() > 0
}